package org.openea.eap.module.obpm.service.custsql;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import org.openbpm.base.core.util.StringUtil;
import org.openea.eap.module.obpm.model.custsql.FormCustSqlFields;
import org.openea.eap.module.obpm.util.custsql.JdbcTemplateUtil;
import org.openea.eap.module.obpm.model.custsql.vo.SqlViewVO;
import org.openbpm.org.api.model.IGroup;
import org.openbpm.org.api.model.IUser;
import org.openbpm.org.api.service.GroupService;
import org.openbpm.org.api.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FormCustSqlFlowExtService {
    @Autowired
    GroupService groupService;

    @Autowired
    UserService userService;

//    @Resource
//    protected WorkCalService workCalService;

    // 记录中添加流程任务属性
    public List<Map<String, Object>> extTaskData(List<Map<String, Object>> queryForList, SqlViewVO sqlViewVO, String bpmExt) {
        if(bpmExt.startsWith("todotask")){
            for(Map<String, Object> row: queryForList){
                TaskVo taskVo = convertTaskVo(row);
                row.put("bpm_task_ext", taskVo);
            }
        }
        return queryForList;
    }

    // 多实例会签节点有问题
    public List<Map<String, Object>> extFlowData(List<Map<String, Object>> queryForList, SqlViewVO sqlViewVO) {
        String columnBizId = "biz_id_";
        if (StringUtil.isNotEmpty(sqlViewVO.getBpmExtColumnBizId())) {
            columnBizId = sqlViewVO.getBpmExtColumnBizId();
        }
        // bus PK

        // 支持方案
        // 1-指定流程字段，数据通过改字段扩展（推荐，可支持多类流程）
        // 2-指定为流程，数据通过固定的bpm_flow_ext, 关联字段为指定流程实例字段（只支持单类流程）
        // 3-指定为流程，数据通过固定的bpm_flow_ext, 关联字段为业务主键或指定业务字段

        // TODO 暂时只支持一个流程，可扩展为支持多个流程，需要前后端配合修改
        String bpmFlowField = null;
        for(FormCustSqlFields field: sqlViewVO.getFieldList()){
            // control type 22 - 流程字段
            if(22 == field.getControlType()){
                bpmFlowField = field.getFieldName();
                break;
            }
        }
        if(StringUtil.isEmpty(bpmFlowField)){
            bpmFlowField = "bpm_inst_id";
        }


        // 1. 检查流程扩展字段以及关联ID
        Set<String> setInstIds = new HashSet<>();
        Set<String> setBizIds = new HashSet<>();
        for (Map<String, Object> rowData : queryForList) {
            if (rowData.containsKey(bpmFlowField)) {
                setInstIds.add(String.valueOf(rowData.get(bpmFlowField)));
                continue;
            }
            if (rowData.containsKey("bpm_flow_ext") && rowData.containsKey(columnBizId)) {
                setBizIds.add(String.valueOf(rowData.get(columnBizId)) );
            }
        }
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        // 2. 根据inst获取流程任务信息
        Map<String, List<TaskVo>> mapInst = new HashMap<>();
        if (!setInstIds.isEmpty()) {
            String instIds = StringUtil.join(setInstIds, "','");
            String queryTasksByInst = "select t.assignee_id_" +
                    " , (select group_concat(pl.identity_ SEPARATOR ';') from bpm_task_identitylink pl where pl.task_id_=t.id_ and pl.type_='user') as assignee_ids_ " +
                    " ,o.* " +
                    " from bpm_task t, bpm_task_opinion o " +
                    " where t.id_=o.task_id_ and t.inst_id_ in ('" + instIds + "') " +
                    " order by t.inst_id_, t.create_time_ asc ";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(queryTasksByInst);
            for (Map<String, Object> map : list) {
                String instId = String.valueOf( map.get("inst_id_"));
                List<TaskVo> tasks = null;
                if (mapInst.containsKey(instId)) {
                    tasks = mapInst.get(instId);
                } else {
                    tasks = new ArrayList<TaskVo>();
                    mapInst.put(instId, tasks);
                }
                tasks.add(convertTaskVo(map));
            }
        }
        // 3. 根据biz获取流程任务信息
        Map<String, List<TaskVo>> mapBiz = new HashMap<>();
        if (!setBizIds.isEmpty()) {
            String bizIds = StringUtil.join(setBizIds, "','");
            String queryTasksByBiz = "select t.*,l.biz_id_" +
                    " , (select group_concat(pl.identity_ SEPARATOR ';') from bpm_task_identitylink pl where pl.task_id_=t.id_ and pl.type_='user') as assignee_ids_ " +
                    " from bpm_task t, bpm_bus_link l " +
                    " where t.inst_id_=l.inst_id_ and l.biz_id_  in ('" + bizIds + "')" +
                    "  order by l.biz_id_, t.create_time_ asc  ";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(queryTasksByBiz);
            for (Map<String, Object> map : list) {
                String bizId = String.valueOf( map.get("biz_id_"));
                List<TaskVo> tasks = null;
                if (mapBiz.containsKey(bizId)) {
                    tasks = mapBiz.get(bizId);
                } else {
                    tasks = new ArrayList<TaskVo>();
                    mapBiz.put(bizId, tasks);
                }
                tasks.add(convertTaskVo(map));
            }
        }
        // 4. 将获取流程任务信息更新回数据列表
        for (Map<String, Object> rowData : queryForList) {
            if(rowData.containsKey(bpmFlowField)){
                JSONObject json = new JSONObject();
                String instId = String.valueOf( rowData.get(bpmFlowField));

                // 过滤无效流程
                if(StringUtil.isEmpty(instId) || "0".equals(instId)){
                    //无数据跳出
                    continue;
                }
                // 过滤暂停流程
                // 修改单: isAbandoned=暂停或作废， 保留"申请作废待处理"
                if(rowData.containsKey("isAbandoned")){
                    String abValue = MapUtil.getStr(rowData,"isAbandoned");
                    if(abValue.indexOf("暂停")>=0){
                        continue;
                    }
                }

                json.put("inst_id", instId);
                List<TaskVo> tasks = mapInst.get(instId);
                if(tasks==null|| tasks.isEmpty()){
                    // 增加流程已经完成的信息
                    // TODO  需要grid配合进行调整
                    //tasks = createTasksForFlowCompleted(instId);

                    // 2022-11-01 15:10:22 @范彦青 流程节点增加 status 信息，用于单元格渲染
                    String status = "";
                    if (StringUtil.isNotEmpty(instId) && !"null".equals(instId)) {
                        try {
                            status = jdbcTemplate.queryForObject("SELECT status_ FROM `bpm_instance` WHERE id_ = '" + instId + "'", String.class);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    json.put("status", status);
                    json.put("completed", "1");
                }
                json.put("tasks", tasks);
                rowData.put("bpm_flow_ext", json);

                continue;
            }
            if (rowData.containsKey("bpm_flow_ext")) {
                if (rowData.containsKey(columnBizId) || rowData.containsKey("bpm_biz_id")) {
                    JSONObject json = new JSONObject();
                    String bizId = String.valueOf(rowData.get(columnBizId));
                    if (StringUtil.isEmpty(bizId)) {
                        bizId = String.valueOf(rowData.get("bpm_biz_id"));
                    }
                    json.put("biz_id_", bizId);
                    List tasks = mapBiz.get(bizId);
                    if(tasks==null|| tasks.isEmpty()){
                        // TODO 增加流程已经完成的信息
                        //tasks = createTasksForFlowCompleted();
                    }
                    json.put("tasks", tasks);
                    rowData.put("bpm_flow_ext", json);
                }
            }
        }
        return queryForList;
    }

    protected List<TaskVo> createTasksForFlowCompleted(String instId){
        if(StringUtil.isEmpty(instId) || "null".equalsIgnoreCase(instId)) {
            return null;
        }
        //增加流程已经完成的信息
        List<TaskVo> tasks = new ArrayList<>();
        TaskVo task = new TaskVo();
        task.setTaskId("0");
        task.setTaskName("已经结束");
        task.setTaskLink("/bpm/vueForm/instanceDetail.html?id="+instId);
        tasks.add(task);
        return tasks;
    }

    public List<Map<String, Object>> extTaskData(List<Map<String, Object>> tasks, List<Map<String, Object>> queryForList, SqlViewVO sqlViewVO) {
        String columnBizId = "biz_id_";
        if (StringUtil.isNotEmpty(sqlViewVO.getBpmExtColumnBizId())) {
            columnBizId = sqlViewVO.getBpmExtColumnBizId();
        }
        Map<String, Map<String, Object>> mapData2 = new HashMap<>();
        for (Map<String, Object> row : queryForList) {
            String bizId =  String.valueOf(row.get(columnBizId));
            if (bizId == null) {
                bizId = String.valueOf(row.get("biz_id_"));
            }
            mapData2.put(bizId, row);
        }
        queryForList = new ArrayList<>();
        for (Map<String, Object> task : tasks) {
            String bizId = String.valueOf(task.get("biz_id_"));
            if (mapData2.containsKey(bizId)) {
                Map<String, Object> mergeTask = new HashMap<>();
                mergeTask.putAll(mapData2.get(bizId));
                TaskVo taskVo = convertTaskVo(task);
                mergeTask.put("bpm_task_ext", taskVo);
                mergeTask.put("taskId", taskVo.getTaskId());
                queryForList.add(mergeTask);
            }
        }
        return queryForList;
    }

    public TaskVo convertTaskVo(Map<String, Object> map) {
        TaskVo task = new TaskVo();

        // task id
        String taskId = null;
        if(map.containsKey("task_id_")){
            taskId = MapUtil.getStr(map, "task_id_");
        }
        if(taskId==null && map.containsKey("id_")){
            taskId= MapUtil.getStr(map, "id_");
        }
        task.setTaskId(taskId);
        // task name
        String taskName = null;
        if(map.containsKey("task_name_")){
            taskName = MapUtil.getStr(map, "task_name_");
        }
        if(taskName==null && map.containsKey("name_")){
            taskName = MapUtil.getStr(map, "name_");
        }
        task.setTaskName(taskName);

        ///bpm/vueForm/taskComplete.html?taskId=418265737050193921
        task.setTaskLink("/bpm/vueForm/taskComplete.html?taskId=" + taskId);
        task.setDefName(MapUtil.getStr(map, "def_name_"));
        int planWorkdays = 999;
        if(map.containsKey("plan_workdays_")){
            try{
                planWorkdays = MapUtil.getInt(map, "plan_workdays_");
            }catch (Exception e){
                //log.warn("can't plan_workdays_:"+ e.getMessage());
            }
        }
        task.setWorkDays("" + planWorkdays);
        int remainDays = 999;
        if(map.containsKey("remain_days_")){
            // TODO 如为每天定时JOB机制则需要检查最后计算时间cal_days_time_是否为当天
            try{
                remainDays =  MapUtil.getInt(map, "remain_days_");
            }catch (Exception e){
                //log.warn("can't remain_days_:"+e.getMessage());
            }
        }
        task.setRemainDays("" + remainDays);
        Date createTime = null;
        if (map.containsKey("create_time_")) {
            createTime = MapUtil.getDate(map, "create_time_");
        }
        if(createTime==null){
            createTime = new Date();
        }
        task.setStartTime(DateUtil.formatDateTime(createTime));

        Date dueTime = null;
        if(map.containsKey("plan_complete_day_")){
            try{
                dueTime = MapUtil.getDate(map, "plan_complete_day_");
            }catch (Exception e){
                //log.warn("can't plan_complete_day_:"+e.getMessage());
            }
        } else if (map.containsKey("due_time_")) {
            try{
                dueTime = MapUtil.getDate(map, "due_time_");
            }catch (Exception e){
                //log.warn("can't due_time_:"+e.getMessage());
            }
        }
        if(dueTime==null){
            // TODO 待补上工作时间计算
            //dueTime = workCalService.getWorkDayByDay(createTime, planWorkdays);
            if(dueTime==null){
                dueTime = new Date();
            }
        }
        task.setDueTime(DateUtil.formatDateTime(dueTime));
        String masterGroupName = MapUtil.getStr(map, "master_group_name_");
        String masterGroup = MapUtil.getStr(map, "master_group_");
        task.setMasterGroup(masterGroup);
        if (StringUtil.isNotEmpty(masterGroup)) {
            IGroup group = groupService.getByCode("org", masterGroup);
            if(group==null){
                group = groupService.getById("org", masterGroup);
            }
            if (group != null) {
                masterGroupName = group.getGroupName();
            }
        }
        if(StringUtil.isEmpty(masterGroupName)){
            masterGroupName = "[管理组(待配置)]";
        }
        task.setMasterGroupName(masterGroupName);

//        private List<String[]> assignees;  //ID/姓名/工号/分机
        List<String[]> assignees = new ArrayList<>();
        String assigneeId = MapUtil.getStr(map, "assignee_id_");

        if (StringUtil.isNotEmpty(assigneeId) && !"0".equals(assigneeId)) {
            String[] userInfo = getAssignee("" + assigneeId);
            if (userInfo != null) {
                assignees.add(userInfo);
            }
        }
        String strIds = MapUtil.getStr(map, "assignee_ids_");
        if ("0".equals(assigneeId) && StringUtil.isNotEmpty(strIds)) {
            String[] aId = strIds.split(";");
            for (String id : aId) {
                String[] userInfo = getAssignee(id);
                if (userInfo != null) {
                    assignees.add(userInfo);
                }
            }
        }

        task.setAssignees(assignees);
        return task;
    }

    private String[] getAssignee(String id) {

        if(StringUtil.isEmpty(id)){
            return null;
        }
        // fix for [1128]
        if (id.startsWith("[") && id.endsWith("]")) {
            id = id.substring(1, id.length() - 2);
        }
        // TODO 此次查询用户服务需要支持缓存来提高效率
        IUser user = userService.getUserById(id);
        if (user != null) {
            return new String[]{user.getUserId(), user.getFullname(), user.getAccount(), (user.getMobile()==null?"":user.getMobile())};
        }
        return null;
    }


    @lombok.Data
    class TaskVo {
        private String taskId;
        private String taskName;
        private String taskLink;

        private String defName;  //流程名称
        private String workDays;  //计划工作天数（整数）
        //private String completeDay; //计划完成日期yyyy-MM-dd
        private String remainDays;  //剩余工作天数（整数，可能为负数）
        private String startTime;  //yyyy-MM-dd HH24:mi:ss
        private String dueTime;  //yyyy-MM-dd HH24:mi:ss

        private String masterGroup;
        private String masterGroupName;
        private List<String[]> assignees;  //ID/姓名/工号/分机

    }

}


